#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <common.h>

#include "parser.h"

cmd_parser:: cmd_parser () {
	for (unsigned i = 0; i < BUF_LEN; i++) // zero out the buffer just in case
		cmd_buf[i] = 0;

	len = BUF_LEN;
	wr_index = 0;
}

cmd_parser:: ~cmd_parser () {
}
/*
void cmd_parser:: buf_realloc () { // increases buffer size
	len += BUF_LEN;
	cmd_buf = (char*) realloc (cmd_buf, len*sizeof(char));
}
*/

// ############################################################################
int cmd_parser:: cmd_parse () {
// use strtok to examine the command
	char* cmd_code_str = strtok (cmd_buf, " "); // space is delimiter
	char* arg = strtok (NULL, " ");
		
	if (cmd_code_str == NULL) {
		return 1;
	}

	int cmd_code = atoi (cmd_code_str);
	int ret;

	if (cmd_code == 9999)
		return -1; // main program exits
	ret = dispatch_cmd_file (cmd_code, arg); // check if its a file command
	if (ret == 0) return 0;
	ret = dispatch_cmd_sing (cmd_code, arg); // check if its a signular cmd
	if (ret == 0) return 0;
	ret = dispatch_cmd_ID (cmd_code, arg); // check if its ID command
	if (ret == 0) return 0;

	printw ("Unrecognized action code.\n");
	return 1;
}

// ############################################################################
int cmd_parser:: cmd_getch (WINDOW* scr) { 
// puts char in buffer. If buffer too small dont accept input
// if char is "enter" then call cmd_parse
	char c = getch ();
	int ret; 
	int x, y;
	//if (c != ERR) printw ("%d\n", (int)c);
	
	if (c == ERR) 
		return 0;
	else if (c == 7) { // backspace
		if (wr_index == 0) { // cant backspace on first space
			beep ();
			return 0;
		}
		
		getyx (scr, y,x); // delete the last letter on screen
		mvdelch (y,x-1);
		wr_index--;	// delete the last letter in buffer
		cmd_buf[wr_index] = 0;
	}
	else if ((c >= 32) && (c <= 126)) { // acceptable char
		if (wr_index == len-2) { // dont accept input if buffer full
			beep ();
			return 0;
		}

		cmd_buf[wr_index] = c;
		wr_index++;
		printw ("%c", c);
	}
	else if (c != '\n') { // unacceptable char
		beep ();
		return 0;
	}
	else { // enter
		printw ("\n");
		
		ret = cmd_parse (); // parse the command and take actions

		wr_index = 0; // flush the buffer
		for (unsigned i = 0; i < len; i++) 
			cmd_buf[i] = 0;
		printw (CMD_LINE);
	}
	return ret;
}

// ############################################################################
int dispatch_cmd_file (int code, const char* filename) {
	// check for file commands
	FILE* fp = NULL;
	if (filename != NULL) fp = fopen (filename, "r"); // open file if valid
/*
	if (fp == NULL) { // change this back later!!
		if ((code==1000)||(code==2000)||(code==2001)||(code==2400)||(code==2401)||
				(code==6000)||(code==8000)||(code==8008)||(code==8888)) {
			printw ("Invalid file name.\n");
			return 0;
		}
		else
			return 1;
	}
*/
	int n1=-1, n2=-1, n3=-1; 
	char str[100];
	str[0] = 0;
	int ret;

	switch (code) {
		case 1000: // connect	// read IP address, port, clientID
			client->connect ("", 7496, 0);
			if (client->isConnected())
				printw ("\nConnection Successful.\n");
/*
			fscanf (fp, "%s %d %d", str, &n1, &n2);
			if ((str[0] == 0) || (n1 < 0) || (n2 < 0))  // an arg was invalid
				printw ("Invalid input file format.\n");
			else 
				printw ("Dispatching: Connect\n"); // call connect function
			ret = 0;
*/
			break;
		case 2000: // req data: ID,security,barsize
			fscanf (fp, "%d %s", &n1, str);
			if ((str[0] == 0) || (n1 < 0))  // an arg was invalid
				printw ("Invalid input file format.\n");
			else 
				printw ("Dispatching: Request Realtime Data\n"); // call connect function
			ret = 0;
			break;
		case 2001: // bar data
			fscanf (fp, "%d %s %d", &n1, str, &n2);
			if ((str[0] == 0) || (n1 < 0) || (n2 < 0))  // an arg was invalid
				printw ("Invalid input file format.\n");
			else 
				printw ("Dispatching: Request Bar Data\n"); // call connect function
			ret = 0;
			break;
		case 2400: // EMA
			fscanf (fp, "%d %s %d %d", &n1, str, &n2, &n3);
			if ((str[0] == 0) || (n1 < 0) || (n2 < 0) || (n3 < 0))  // an arg was invalid
				printw ("Invalid input file format.\n");
			else 
				printw ("Dispatching: Request EMA\n"); // call connect function
			ret = 0;
			break;
		case 2401: // MACD, sig, hist
			fscanf (fp, "%d %s %d", &n1, str, &n2);
			if ((str[0] == 0) || (n1 < 0) || (n2 < 0))  // an arg was invalid
				printw ("Invalid input file format.\n");
			else 
				printw ("Dispatching: Request MACD\n"); // call connect function
			ret = 0;
			break;
		case 6000: // order
		case 8000: // auto trade nonstop
		case 8008: // auto trade with stop
		case 8888: 
			printw ("File command accepted.\n");
			ret = 0;
			break;
		default:
			ret = 1;
	}

	//fclose (fp);
	return ret;
}

// ############################################################################
int dispatch_cmd_sing (int code, const char* arg) {
// these codes dont need any inputs
	if (arg != NULL) {
		if ((code==1001)||(code==1010)||(code==6900)||(code==9000)) {
			printw ("Invalid command format.\n");
			return 0;
		}
		else
			return 1;
	}

	switch (code) {
		case 1001: // disconnect
		case 1010: // time
		case 6900: // clear all pos
		case 9000: // stop auto trade
				printw ("Singular command accepted.\n");
			return 0;
	}
	return 1;
}

// ############################################################################
int dispatch_cmd_ID (int code, const char* arg) {
	int ID = -1;	
	if (arg != NULL) ID = atoi (arg);

	if (ID <= 0) { // atoi failed
		if ((code==3000)||(code==3001)||(code==3400)||(code==3401)||(code==6001)){
			printw ("Invalid ID.\n");
			return 0;
		}
		else
			return 1;
	}

	switch (code) {
		// these need an id
		case 3000: // cancel data
		case 3001: // cancel bar
		case 3400: // cancel EMA
		case 3401: // cancel MACD
		case 6001: // cancel order
			printw ("ID command accepted. ID=%d\n", ID);
			return 0;
	}
	return 1;
}	

